/*
Copyright © 2022 NAME HERE <EMAIL ADDRESS>

*/
package cmd

import (
	"context"
	"errors"
	"os"
	"os/signal"

	"gitee.com/bjf-fhe/apicat/config"
	"gitee.com/bjf-fhe/apicat/source/nginx"
	"github.com/sirupsen/logrus"
	"github.com/spf13/cobra"

	_ "gitee.com/bjf-fhe/apicat/platform/aliyun"
	_ "gitee.com/bjf-fhe/apicat/platform/aws"
	_ "gitee.com/bjf-fhe/apicat/platform/echo"
	_ "gitee.com/bjf-fhe/apicat/platform/nginx"
)

var signalChan = make(chan os.Signal, 1)
var runningCtx context.Context
var runningCancel context.CancelFunc

// rootCmd represents the base command when called without any subcommands
var rootCmd = &cobra.Command{
	Use:   "apicat",
	Short: "OpenAPI日志分析程序",
	Long: `结合OpenAPI定义，分析Nginx访问日志，发现恶意访问，提高安全级别。
	
	使用方法：
	生成访问分析报告：	apicat report
	监听访问日志：		apicat watch
	
	具体使用方法请在命令后加--help获取`,
	PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
		if rootConfig.RemoteAggregationAsSub && rootConfig.RemoteAggregationAsMain {
			return errors.New("不能同时设置--main和--sub参数，请设置main作为主服务器，sub作为子服务器")
		} else if rootConfig.RemoteAggregationMainServer != "" && !rootConfig.RemoteAggregationAsMain && !rootConfig.RemoteAggregationAsSub {
			return errors.New("如果设置了--main-server参数，必须设置--main或--sub参数")
		}
		signal.Notify(signalChan, os.Interrupt)
		return initializeConfig(cmd)
	},
}

func Execute() {
	err := rootCmd.Execute()
	if err != nil {
		os.Exit(1)
	}
}

func init() {
	go func() {
		<-signalChan
		logrus.Infoln("收到中断信号，正在退出程序")
		runningCancel()
	}()

	runningCtx, runningCancel = context.WithCancel(context.Background())

	rootCmd.PersistentFlags().StringVarP(&rootConfig.Definition, "definition", "d", "./openapi.yaml", "OpenAPI definition")
	rootCmd.PersistentFlags().StringVarP(&rootConfig.Config, "config", "c", "./apicat.yaml", "配置文件路径")
	rootCmd.PersistentFlags().StringVarP(&rootConfig.UserName, "username", "u", "", "百家饭平台用户名/手机号/邮箱")
	rootCmd.PersistentFlags().StringVarP(&rootConfig.Password, "password", "p", "", "百家饭平台用户密码")

	rootCmd.PersistentFlags().StringVarP(&rootConfig.Server, "server", "s", "0", "选择使用那个服务器，可以输入'/'或者数字编号，数字编号对应OpenAPI服务器配置的编号，默认为0，也就是从OpenAPI文档中选择第一个")
	rootCmd.PersistentFlags().StringSliceVar(&rootConfig.ServerVariables, "server_variables", nil, "如果服务器地址有参数存在，可以通过该参数传入变量，输入形式为名称:值")
	rootCmd.PersistentFlags().StringSliceVar(&rootConfig.StaticFileTypes, "static_types", config.DefaultStaticFileTypes, "静态文件的后缀，列表中的文件类型会被认为是静态文件")
	rootCmd.PersistentFlags().StringVar(&rootConfig.WellknownAPIs, "wellknown", "", "一些常见的未定义url")
	rootCmd.PersistentFlags().StringVar(&rootConfig.SourceMode, "source", "nginx", "日志来源模式，支持nginx/aliyun/aws")
	rootCmd.PersistentFlags().IntVar(&rootConfig.Debug, "log-level", int(logrus.WarnLevel), "日志级别，默认为3（Warning），可设置0（Panic）-1（Fatal）-2（Error）-4（Info）-5（Debug）-6（Trace）")
	rootCmd.PersistentFlags().StringVar(&rootConfig.TimeFormat, "time-formate", nginx.DefaultLocalTimeFormat, "默认时间格式，Nginx模式用于解析time_local,对time_iso8601无效")

	rootCmd.PersistentFlags().StringVar(&rootConfig.DbName, "cache-db", "./apicat.db", "缓存数据库文件路径")
	rootCmd.PersistentFlags().IntVar(&rootConfig.IPHashLength, "ip-hash-length", 32, "IP地址哈希长度，用于设置缓存IP地址的哈希值长度，长度越大，精度越高，但内存占用越大")

	rootCmd.PersistentFlags().BoolVar(&rootConfig.RemoteAggregationAsMain, "main", false, "是否启用远程聚合模式，并作为汇聚机，启用后，会监听并等待远程链接，并将远程聚合的结果作为主要结果")
	rootCmd.PersistentFlags().BoolVar(&rootConfig.RemoteAggregationAsSub, "sub", false, "是否启用远程聚合模式，并作为子机，启用后，会连接远程汇聚机，并将本地聚合的结果发送给远程汇聚机")
	rootCmd.PersistentFlags().StringVar(&rootConfig.RemoteAggregationMainServer, "main-server", "", "远程聚合模式的汇聚机地址，格式为ip:port, main模式下作为监听地址，sub模式下作为连接地址")

	// Cobra also supports local flags, which will only run
	// when this action is called directly.
	// rootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
}
